import { AuthPayload } from '../../types/graphql'
import db from '@/util/db'
import { ApolloClient, onLogin, onLogout } from '@/util/graphql'
import { RegisterInput, RegisterPayload } from '@/types'
import {
  VuexModule,
  Module,
  Mutation,
  Action,
  RegisterOptions
} from 'vuex-class-modules'
import { store } from '../store'
import { to } from '@/util/util'

interface PlayerInfo {
  id: string
  name: string
  characterUrl: string
}
const keyPlayerInfo = 'PLAYER_INFO'
const keyPlayerAuth = 'apollo-token'

@Module
class PlayerModule extends VuexModule {
  player: PlayerInfo
  authToken: string = ''

  constructor(optios: RegisterOptions) {
    super(optios)
    this.player = db.get<PlayerInfo>(keyPlayerInfo, () => ({
      id: '',
      name: '',
      characterUrl: ''
    }))
    this.authToken = db.get<string>(keyPlayerAuth, () => '')
  }

  @Mutation
  SetPlayerInfo(playerInfo: PlayerInfo) {
    this.player = playerInfo
    // save in db
    db.save<PlayerInfo>(keyPlayerInfo, playerInfo)
  }

  @Mutation
  SetAuthToken(token: string) {
    this.authToken = token
    // save in db
    db.save(keyPlayerAuth, token)
  }

  // ClearAll clear all state(token and playerInfo)
  @Mutation
  ClearAll() {
    this.player = {
      characterUrl: '',
      id: '',
      name: ''
    }
    this.authToken = ''
    db.remove(keyPlayerAuth)
    db.remove(keyPlayerInfo)
  }

  @Action
  async register({
    input,
    graphqlClient
  }: {
    input: RegisterInput
    graphqlClient: ApolloClient<any>
  }) {
    const response = await graphqlClient.mutate({
      mutation: require('@/graphql/register.gql'),
      variables: {
        input: input
      }
    })

    let data: RegisterPayload = response.data.register

    const playerInfo: PlayerInfo = {
      characterUrl: data.player.character.imgUrl,
      id: data.player.id,
      name: data.player.name
    }
    // mutate state
    this.SetAuthToken(data.token)
    this.SetPlayerInfo(playerInfo)

    onLogin(graphqlClient)
    return data
  }

  @Action
  async login({
    loginToken,
    graphqlClient
  }: {
    loginToken: string
    graphqlClient: ApolloClient<any>
  }) {
    const response = await graphqlClient.mutate({
      mutation: require('@/graphql/login.gql'),
      variables: {
        loginToken
      }
    })

    if (response.errors) {
      return
    }

    let data: AuthPayload = response.data.login

    const playerInfo: PlayerInfo = {
      characterUrl: data.player.character.imgUrl,
      id: data.player.id,
      name: data.player.name
    }
    // mutate state
    this.SetAuthToken(data.token)
    this.SetPlayerInfo(playerInfo)

    // callback
    onLogin(graphqlClient)
  }

  @Action
  async logout(graphqlClient: ApolloClient<any>) {
    await graphqlClient.mutate({
      mutation: require('@/graphql/mtLogout.gql')
    })
    // mutate state
    this.SetAuthToken('')
    this.SetPlayerInfo({
      characterUrl: '',
      id: '',
      name: ''
    })

    onLogout(graphqlClient)
  }
}

export const playerModule = new PlayerModule({ store, name: 'player' })
